package com.cloud.api.common.log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Program: aop
 * @ClassName SysLogger
 * @Description: aop日志具体实现
 * @Author: liutao
 * @DateTime: 2022/6/5 2:38
 * @Version: 1.0
 */

@EnableBinding(value = Source.class)
@Aspect
@Component
public class CloudApiLogger {

    /**
     * spring cloud stream里面发消息通过 Source 发送
     */
    @Autowired
    private Source source;

    private CloudApiLog logs = new CloudApiLog();

    private final Logger logger = LoggerFactory.getLogger(CloudApiLogger.class);

    @Value("${spring.application.name}")
    private String SpringApplicationName;


    private ThreadLocal startTime = new ThreadLocal<Long>();

    @Pointcut("@annotation(com.cloud.api.common.log.CloudApiAnnotation)")
    public void operLoggerPointCut() {
        logger.info("===============系统操作日志===============");
    }

    @Pointcut("execution(public * com.cloud.api.*.controller.*.*(..))")
    public void controllerMethod() {
    }

    @Before("operLoggerPointCut()")
    public void logBefore(JoinPoint joinPoint) {

        startTime.set(System.currentTimeMillis());
        Map<String, String> map = System.getenv();
        String userName = map.get("USERNAME");// 获取// 用户名


        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        StringBuilder requestLog = new StringBuilder();
        Signature signature = joinPoint.getSignature();
        Method method = ((MethodSignature) signature).getMethod();
        CloudApiAnnotation sysAnnotation = method.getAnnotation(CloudApiAnnotation.class);//利用反射获取到自定义注解


        // 打印请求内容
        logger.info("===============请求内容开始===============");
        logger.info("请求时间:" + new Date());


        logger.info("开发电脑昵称:" + userName);
        logs.setUserName(userName);
        logger.info("服务模块:" + SpringApplicationName);
        logs.setSpringApplicationName(SpringApplicationName);
        logger.info("操作模块：" + sysAnnotation.operMoudle());
        logs.setOperationModular(sysAnnotation.operMoudle());
        logger.info("操作方法：" + sysAnnotation.operMethod());
        logs.setOperationMethod(sysAnnotation.operMethod());
        logger.info("操作描述：" + sysAnnotation.operDes());
        logs.setOperationDes(sysAnnotation.operDes());
        logger.info("请求地址:" + request.getRequestURL().toString());
        logs.setRequestURL(request.getRequestURL().toString());
        logger.info("请求IP:" + request.getRemoteAddr());
        logs.setRequestIp(request.getRemoteAddr());
        logger.info("请求方式:" + request.getMethod());
        logs.setRequestMethod(request.getMethod());
        logger.info("请求类方法:" + joinPoint.getSignature());
        logs.setRequestSignature(joinPoint.getSignature().toString());
        logger.info("请求类方法参数值:" + Arrays.toString(joinPoint.getArgs()));


        // 处理请求参数
        String[] paramNames = ((MethodSignature) signature).getParameterNames();
        Object[] paramValues = joinPoint.getArgs();
        int paramLength = null == paramNames ? 0 : paramNames.length;
        if (paramLength == 0) {
            requestLog.append(" {} ");
        } else {
            requestLog.append(" {");
            for (int i = 0; i < paramLength - 1; i++) {
                requestLog.append(paramNames[i]).append("=").append(JSONObject.toJSONString(paramValues[i])).append(",");
            }
            requestLog.append(paramNames[paramLength - 1]).append("=").append(JSONObject.toJSONString(paramValues[paramLength - 1])).append("}");
        }
        logger.info("请求参数明细:" + requestLog.toString());
        logs.setRequestArgs(requestLog.toString());
        logger.info("===============请求内容结束===============");


    }

    @AfterReturning(returning = "o", pointcut = "operLoggerPointCut()")
    public void logResultVOInfo(Object o) {
        long l = System.currentTimeMillis() - (long) startTime.get();

        System.out.println((long) startTime.get());
        System.out.println(System.currentTimeMillis());

        logger.info("--------------返回内容开始----------------");
        logger.info("Response内容:" + JSON.toJSONString(o));

        logs.setResult(o.toString());
        logger.info("--------------返回内容结束----------------");
        logger.info("--------------操作耗时----------------");
        logger.info(": " + l);
        logs.setRequestTime(l);

        //TODO RockMQ 发送消息
        boolean send = source.output()
                .send(MessageBuilder.withPayload(JSONObject.toJSONString(logs))
                        .build());
        System.out.println(send);
    }

    @AfterThrowing(pointcut = "controllerMethod()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("连接点方法为：" + methodName + ",参数为：" + args + ",异常为：" + ex);

    }
}
